package com.toutiao.model

import org.iq80.leveldb.Options
import org.iq80.leveldb.DB
import org.iq80.leveldb.DBIterator
import org.iq80.leveldb.CompressionType
import org.fusesource.leveldbjni.JniDBFactory.{factory => LevelFactory}

import java.io.File

import java.io.PrintWriter

import scala.collection.mutable.ArrayBuffer

import org.apache.log4j.Logger

import com.toutiao.score.Topic

class FeatureDB(location:String, cacheSize:Int) {
  
  private val log = Logger.getLogger(this.getClass.getName)
  
  val op = new Options
  op.createIfMissing(true)
  op.cacheSize(cacheSize*1024*1024)
  op.writeBufferSize(32*1024*1024)
  op.blockSize(16*1024)
  op.maxOpenFiles(65536)
  op.compressionType(CompressionType.NONE)
  
  val db = LevelFactory.open(new File(location),op)
  
  def isIn(name:String) = {
    val k = name.getBytes
    val v = db.get(k)
    v != null
  }
    
  def apply(name:String) = {
    val k = name.getBytes
    //val v = new String(db.get(k))
    //_log.info(v)
    //Converter.parseLine(v)
    val v = db.get(k)
    Converter.parseData(v)
  }

  def getValue(n:String) = {
    val k = n.getBytes
    //val v = new String(db.get(k))
    //v
    db.get(k)
  }
  
  def _get(n:String) = {
    val k = n.getBytes
    //val v = new String(db.get(k))
    //v
    db.get(k)
  }
  
  def mget(ns:Array[String]) = {
    val vs = ns.map(n => {
      (n,_get(n))
    })
    vs.par.map(nv => {
      val n = nv._1
      val v = nv._2
      //(n,Converter.parseLine(v))
      (n,Converter.parseData(v))
    }).seq.toMap
  }
  
  def insert(name:String,topic:Topic) {
    val k = name.getBytes
    //val v = Converter.convertLine(event).getBytes
    val v = Converter.convertData(topic)
    db.put(k, v)
  }
  
  def remove(name:String) {
    val k = name.getBytes
    db.delete(k)
  }
  
  def close = db.close
  
  def getData = {
    val xs = new ArrayBuffer[Topic]
    val iterator = db.iterator
    try {
      iterator.seekToFirst
      while (iterator.hasNext){
        val u = iterator.peekNext
        val k = new String(u.getKey)
        //val v = new String(u.getValue)
        val v = u.getValue
        val t = Converter.parseData(v)
        xs += t
        iterator.next
      }
     
    } finally {
      iterator.close
    }    
    xs.toArray
  }
  
  def getKeys = {
    val xs = new ArrayBuffer[String]
    val iterator = db.iterator
    try {
      iterator.seekToFirst
      while (iterator.hasNext){
        val u = iterator.peekNext
        val k = new String(u.getKey)
        
        xs += k
        iterator.next
      }
     
    } finally {
      iterator.close
    }    
    xs.toArray    
  }
  
  
  def getKVs = {
    val xs = new ArrayBuffer[(String,Topic)]
    val iterator = db.iterator
    try {
      iterator.seekToFirst
      while (iterator.hasNext){
        val u = iterator.peekNext
        val k = new String(u.getKey)
        //val v = new String(u.getValue)
        val v = u.getValue
        val t = Converter.parseData(v)
        xs.append((k,t))
        iterator.next
      }
     
    } finally {
      iterator.close
    }    
    xs.toArray    
  }
  
  
  def save(location:String) {
    val out = new PrintWriter(location)
    
    val iterator = db.iterator
    try {
      iterator.seekToFirst
      while (iterator.hasNext){
        val u = iterator.peekNext
        val k = new String(u.getKey)
        val v = new String(u.getValue)
        val vv = Converter.parseTopic(v)
        val vvv = Converter.convertTopic(vv)
        val line = k+"\t"+vvv+"\n"
        out.write(line)
        iterator.next
      }
     
    } finally {
      iterator.close
    }
    
    out.close
  }    
  
}